package cn.jbolt.core.plugin;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.annotation.TableBind;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.db.datasource.JBoltDataSourceUtil;
import cn.jbolt.core.db.dbpro.JBoltDbProFactory;
import cn.jbolt.core.model.base.JBoltBaseModel;
import cn.jbolt.core.model.base.JBoltModelConfig;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.IDataSourceProvider;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * JBolt自动绑定model与table的ActiveRecordPlugin
 *
 * @ClassName: JBoltActiveRecordPlugin
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2020年6月17日
 */
public class JBoltActiveRecordPlugin extends ActiveRecordPlugin {
	private static final Log LOG = Log.getLog(JBoltActiveRecordPlugin.class);
	private List<String> autoBindPackages;
	private String databaseName;
	private String schema;

	public JBoltActiveRecordPlugin(IDataSourceProvider dataSourceProvider) {
		super(dataSourceProvider);
		this.databaseName = JBoltConfig.MAIN_DB_NAME;
		this.schema       = JBoltConfig.MAIN_DB_SCHEMA;
		autoBindPackages  = new ArrayList<String>();
		setDbProFactory(new JBoltDbProFactory());
	}

	public JBoltActiveRecordPlugin(String databaseName,String schema,IDataSourceProvider dataSourceProvider) {
		super(dataSourceProvider);
		this.databaseName = StrKit.defaultIfBlank(databaseName,JBoltConfig.MAIN_DB_NAME);
		this.schema = StrKit.defaultIfBlank(schema,JBoltConfig.MAIN_DB_SCHEMA);
		autoBindPackages = new ArrayList<String>();
		setDbProFactory(new JBoltDbProFactory());
	}

	public JBoltActiveRecordPlugin(String configName,String databaseName,String schema,IDataSourceProvider dataSourceProvider) {
		super(configName, dataSourceProvider);
		this.databaseName = StrKit.defaultIfBlank(databaseName,JBoltConfig.MAIN_DB_NAME);
		this.schema = StrKit.defaultIfBlank(schema,JBoltConfig.MAIN_DB_SCHEMA);
		autoBindPackages = new ArrayList<String>();
		setDbProFactory(new JBoltDbProFactory());
	}

	/**
	 * 显示指明需要定向扫描 package
	 *
	 * @param autoBindPackage
	 */
	public void addAutoBindPackage(String autoBindPackage) {
		if (StrKit.notBlank(autoBindPackage)) {
			if (autoBindPackage.indexOf(",") == -1) {
				autoBindPackages.add(autoBindPackage.trim());
			} else {
				List<String> packages = StrUtil.splitTrim(autoBindPackage, ',');
				if (packages != null && packages.size() > 0) {
					autoBindPackages.addAll(packages);
				}
			}
		}
	}

	@Override
	public boolean start() {
		// 处理自动绑定Model-Table映射关系
		processAutoBindTable();
		return super.start();
	}

	/**
	 * 处理自动绑定Model-Table映射关系
	 */
	public void processAutoBindTable() {
		if (autoBindPackages == null || autoBindPackages.size() == 0) {
			String msg = String.format("当前扫描数据源 configName:%s,Model未设置model_package,如果此数据源不使用Model，可忽略此信息。",
					config.getName());
			LOG.warn(msg);
//			throw new RuntimeException(msg);
			return;
		}
		for (String autoBindPackage : autoBindPackages) {
			processAutoBindTable(autoBindPackage);
		}
	}

	/**
	 * 处理自动绑定Model-Table映射关系
	 *
	 * @param autoBindPackage
	 */
	@SuppressWarnings("unchecked")
	private void processAutoBindTable(String autoBindPackage) {
		LOG.debug(String.format("正在扫描%s需要自动绑定数据表映射关系的Model", "包[" + autoBindPackage + "]下"));
		LOG.debug("当前ActiveRecordPlugin:configName=" + config.getName());
		Set<Class<?>> classSet = ClassUtil.scanPackageByAnnotation(autoBindPackage, TableBind.class);
		if (classSet == null || classSet.isEmpty()) {
			LOG.error(String.format("%s没有发现任何需要自动绑定数据表映射关系的Model", "包[" + autoBindPackage + "]下"));
			return;
		}
		classSet.forEach(clazz -> {
			processOneModelMapping((Class<? extends JBoltBaseModel<?>>) clazz);
		});
		LOG.debug(String.format("已完成%s的Model自动扫描与绑定", "包[" + autoBindPackage + "]下"));
	}

	/**
	 * 处理一个Model 映射关系
	 *
	 * @param clazz
	 */
	private void processOneModelMapping(Class<? extends JBoltBaseModel<?>> clazz) {
		TableBind tableBind = clazz.getAnnotation(TableBind.class);
		if (tableBind.dataSource().equals(config.getName())) {
			LOG.debug(String.format("正在处理Model:%s,创建映射关系", clazz.getName()));
			this.addMapping(tableBind.table(), tableBind.primaryKey(), clazz);
			JBoltDataSourceUtil.me.init();
			JBoltModelConfig.me.addConfig(clazz,databaseName,schema);
		}
	}
}
